package com.ziki.common.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;

import com.ziki.common.util.io.IOUtil;
import com.ziki.common.util.string.StrUtil;

public class PropertiesUtil {
    private Properties props = new Properties();
    private String propertiesFile;

    public PropertiesUtil(String propertiesFile) {
        load(propertiesFile);
    }

    private void load(String propertiesFile) {
        InputStream in = null;
        this.propertiesFile = propertiesFile;
        try {
            props = new Properties();
            in = new BufferedInputStream(new FileInputStream(propertiesFile));
            props.load(in);
        } catch (Exception e) {
            throw new RuntimeException("Could not load properties: " + e.getMessage());
        } finally {
            IOUtil.close(in);
        }
    }

    public Set<Object> getKeys() {
        return props.keySet();
    }

    public String getProperty(Object key) {
        return getProperty(StrUtil.parseStr(key), null);
    }

    public String getProperty(String key) {
        return getProperty(key, null);
    }

    public String getProperty(String key, String def) {
        String val = props.getProperty(key, def);
        if (val == null) {
            return def;
        }
        val = val.trim();
        return (val.length() == 0) ? def : val;
    }

    public String[] getArrayProperty(String name) {
        return getArrayProperty(name, null);
    }

    public String[] getArrayProperty(String name, String[] def) {
        String vals = getProperty(name);
        if (vals == null) {
            return def;
        }
        StringTokenizer stok = new StringTokenizer(vals, ",");
        ArrayList<String> strs = new ArrayList<String>();
        try {
            while (stok.hasMoreTokens()) {
                strs.add(stok.nextToken().trim());
            }
            return (String[]) strs.toArray(new String[strs.size()]);
        } catch (Exception e) {
            return def;
        }
    }

    public boolean getBooleanProperty(String name) {
        return getBooleanProperty(name, false);
    }

    public boolean getBooleanProperty(String name, boolean def) {
        String val = getProperty(name);
        return (val == null) ? def : Boolean.valueOf(val).booleanValue();
    }

    public double getDoubleProperty(String name) throws NumberFormatException {
        String val = getProperty(name);
        if (val == null) {
            throw new NumberFormatException(" null string");
        }

        try {
            return Double.parseDouble(val);
        } catch (NumberFormatException nfe) {
            throw new NumberFormatException(" '" + val + "'");
        }
    }

    public double getDoubleProperty(String name, double def) throws NumberFormatException {
        String val = getProperty(name);
        if (val == null) {
            return def;
        }

        try {
            return Double.parseDouble(val);
        } catch (NumberFormatException nfe) {
            throw new NumberFormatException(" '" + val + "'");
        }
    }

    public float getFloatProperty(String name) throws NumberFormatException {
        String val = getProperty(name);
        if (val == null) {
            throw new NumberFormatException(" null string");
        }

        try {
            return Float.parseFloat(val);
        } catch (NumberFormatException nfe) {
            throw new NumberFormatException(" '" + val + "'");
        }
    }

    public float getFloatProperty(String name, float def) throws NumberFormatException {
        String val = getProperty(name);
        if (val == null) {
            return def;
        }

        try {
            return Float.parseFloat(val);
        } catch (NumberFormatException nfe) {
            throw new NumberFormatException(" '" + val + "'");
        }
    }

    public int getIntProperty(String name) throws NumberFormatException {
        String val = getProperty(name);
        if (val == null) {
            throw new NumberFormatException(" null string");
        }

        try {
            return Integer.parseInt(val);
        } catch (NumberFormatException nfe) {
            throw new NumberFormatException(" '" + val + "'");
        }
    }

    public int getIntProperty(String name, int def) throws NumberFormatException {
        String val = getProperty(name);
        if (val == null) {
            return def;
        }

        try {
            return Integer.parseInt(val);
        } catch (NumberFormatException nfe) {
            throw new NumberFormatException(" '" + val + "'");
        }
    }

    public String[] getPropertyGroups(String prefix) {
        Enumeration<?> keys = props.propertyNames();
        HashSet<String> groups = new HashSet<String>(10);

        if (!prefix.endsWith(".")) {
            prefix += ".";
        }

        while (keys.hasMoreElements()) {
            String key = (String) keys.nextElement();
            if (key.startsWith(prefix)) {
                String groupName = key.substring(prefix.length(), key.indexOf('.', prefix.length()));
                groups.add(groupName);
            }
        }

        return (String[]) groups.toArray(new String[groups.size()]);
    }

    public Properties getPropertyGroup(String prefix) {
        return getPropertyGroup(prefix, false, null);
    }

    public Properties getPropertyGroup(String prefix, boolean stripPrefix) {
        return getPropertyGroup(prefix, stripPrefix, null);
    }

    public Properties getPropertyGroup(String prefix, boolean stripPrefix, String[] excludedPrefixes) {
        Enumeration<?> keys = props.propertyNames();
        Properties group = new Properties();

        if (!prefix.endsWith(".")) {
            prefix += ".";
        }

        while (keys.hasMoreElements()) {
            String key = (String) keys.nextElement();
            if (key.startsWith(prefix)) {

                boolean exclude = false;
                if (excludedPrefixes != null) {
                    for (int i = 0; (i < excludedPrefixes.length) && (exclude == false); i++) {
                        exclude = key.startsWith(excludedPrefixes[i]);
                    }
                }

                if (exclude == false) {
                    String value = getProperty(key, "");
                    if (stripPrefix) {
                        group.put(key.substring(prefix.length()), value);
                    } else {
                        group.put(key, value);
                    }
                }
            }
        }

        return group;
    }

    public void setProperty(String key, String value) {
        props.put(key, value);
    }

    public void save() {
        OutputStream os = null;
        try {
            os = new BufferedOutputStream(new FileOutputStream(propertiesFile));
            props.store(os, "");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            IOUtil.close(os);
        }
    }
}
